/*
 * FileName: myMyVector.cc
 * Author: 李波(Edwin Lee)
 * Date: 2024-07-27 16:27:42
 * Version: 1.0
 * Description: 写一个模仿MyVector的myMyVector，着重写emplace_back方法的实现 
 */
#include <cstdlib>
#include <iostream>

using namespace std;

class Test
{
public:
	Test(int a){cout<<"Test(int)"<<endl;}
	Test(int a,int b){cout<<"Test(int,int)"<<endl;}
	Test(const Test& t){cout<<"const Test(Test&)"<<endl;}
	Test(Test&& t){cout<<"Test(Test&&)"<<endl;}
	~Test(){cout<<"~Test()"<<endl;}

};

// 实现容器的空间配置器
template<typename T>
struct MyAllocator
{
	T* allocate(int size)
	{
		return (T*)malloc(size*sizeof(T));
	}

	template<typename... Types>
	void construct(T* ptr,Types&&... args)
	{
		new (ptr) T(std::forward<Types>(args)...);
	}
	
};

template<typename T,typename Alloc = MyAllocator<T>>
class MyVector
{
public:
	MyVector():ptr_(nullptr),size_(0),idx_(0){}
	// 预留内存空间
	void reserve(size_t size)
	{
		ptr_ = allocator_.allocate(size);
		size_ = size;
	}
/*
	void push_back(const T& val)
	{
		allocator_.construct(ptr_+idx_,val);
		++idx_;
	}

	void push_back(const T&& val)
	{
		allocator_.construct(ptr_+idx_,std::move(val));
		++idx_;
	}
*/

	template<typename Type>
	void push_back(Type&& val)
	{
		allocator_.construct(ptr_+idx_,std::forward<Type>(val));
		++idx_;
	}

	// 引用折叠 左值 右值
	template<typename... Types>
	void emplace_back(Types&&... args)
	{
		//不管是左值引用、右值引用变量，它本身是个左值。传递
		//过程中要保持args的引用类型完美转发使用std::forward
		allocator_.construct(ptr_+idx_,std::forward<Types>(args)...);
		++idx_;
	}

private:
	T* ptr_;
	int size_;
	int idx_;
	Alloc allocator_;
};

void test1()
{
	Test t1(10);
	MyVector<Test> vec;
	vec.reserve(100);
	
	cout<<"--------------------------------"<<endl;
	// 直接插入对象，调用左值拷贝函数，两者是没有区别的
	vec.push_back(t1);
	vec.emplace_back(t1);
	
	cout<<"--------------------------------"<<endl;
	// 插入临时变量，调用右值拷贝函数，两者没有区别
	vec.push_back(Test(20));
	vec.emplace_back(Test(20));

	cout<<"--------------------------------"<<endl;
	// 给emplace传入Test对象构造所需要的参数，直接在容器底层构造对象即可
	vec.emplace_back(20);
	vec.emplace_back(30,40);

	cout<<"--------------------------------"<<endl;

}
int main()
{
	test1();
	return 0;
}
